package com.inspur.edp.web.relycheck.dependencyvalidator.element;

import com.inspur.edp.cef.designtime.api.element.GspElementDataType;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.lcm.metadata.spi.entity.ValidateResult;
import com.inspur.edp.web.common.utility.ListUtility;
import com.inspur.edp.web.designschema.elements.ComplexField;
import com.inspur.edp.web.designschema.elements.Entity;
import com.inspur.edp.web.designschema.elements.Field;
import com.inspur.edp.web.designschema.elements.Schema;
import com.inspur.edp.web.designschema.generator.SchemaBuilder;
import com.inspur.edp.web.relycheck.constant.ValidateConstants;
import com.inspur.edp.web.relycheck.dependencygenerator.entity.SourceElementField;
import com.inspur.edp.web.relycheck.elements.CustomEntity;
import com.inspur.edp.web.relycheck.elements.CustomField;
import com.inspur.edp.web.relycheck.utility.StringConcatUtility;
import com.inspur.edp.web.relycheck.utility.ValidateResultUtility;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 数据类型验证
 *
 * @author noah
 * 2023/8/10 16:50
 */
public class DataTypeValidator extends BaseElementValidator {
    @Override
    public ValidateResult validate(ElementValidateParameter parameter) {
        ValidateResult warningValidateResult = ValidateResultUtility.success();

        SchemaBuilder schemaBuilder = new SchemaBuilder();
        GspViewModel targetViewModel = (GspViewModel) parameter.getViewModelMetadata().getContent();
        // 通过当前的ViewModel构造出来对应的表单schema节点
        Schema schema = schemaBuilder.buildWithScene(targetViewModel, "", false);
        Optional<Field> optionalTargetFindField = this.findFieldInFormSchema(schema, parameter.getSourceElementField());

        // 如果查找到目标 Field
        if (optionalTargetFindField.isPresent()) {
            GspElementDataType voFieldType = parameter.getGspViewModelElement().getMDataType();
            Field targetFindField = optionalTargetFindField.get();
            CustomField sourceField = this.getSourceField(parameter);
            // 字段类型比较
            if (!sourceField.getType().get$type().equals(targetFindField.getType().get$type())) {
                return ValidateResultUtility.failureWithError(String.format("视图对象%1$s中子表%2$s的字段%3$s类型变更为" + ValidateConstants.Colon + "%4$s" + ValidateConstants.Comma + "而表单字段类型为" + ValidateConstants.Colon + "%5$s" + ValidateConstants.Comma + "实际应为" + ValidateConstants.Colon + "%6$s" + ValidateConstants.Comma + "请在表单%7$s的实体树中执行更新schema操作",
                        StringConcatUtility.concatWithNamePrefix(this.getVoMetadataName(parameter), true),
                        StringConcatUtility.concatWithCodePrefix(this.getEntityCode(parameter), true),
                        StringConcatUtility.concatWithCodePrefix(this.getSourceFieldCode(parameter), true),
                        StringConcatUtility.concat("", voFieldType.name(), true),
                        StringConcatUtility.concat("", sourceField.get$type(), true),
                        StringConcatUtility.concat("", targetFindField.get$type(), true),
                        StringConcatUtility.concatWithNamePrefix(this.getFormMetadataName(parameter), true)
                ));
            }

            // 复杂类型更换  例如 从人员 UDT 更改为 部门 UDT
            if (targetFindField instanceof ComplexField) {
                ComplexField targetComplexField = (ComplexField) targetFindField;

                if (!sourceField.getType().getName().equals(targetComplexField.getType().getName())) {
                    return ValidateResultUtility.failureWithError(String.format("视图对象%1$s中子表%2$s的字段%3$s的引用关系由" + ValidateConstants.Colon + "%4$s调整为" + ValidateConstants.Colon + "%5$s" + ValidateConstants.Comma + "请在表单%6$s的实体树中执行更新schema操作",
                            StringConcatUtility.concatWithNamePrefix(this.getVoMetadataName(parameter), true),
                            StringConcatUtility.concatWithCodePrefix(this.getEntityCode(parameter), true),
                            StringConcatUtility.concatWithCodePrefix(this.getSourceFieldCode(parameter), true),
                            StringConcatUtility.concat("", sourceField.getType().getName(), true),
                            StringConcatUtility.concat("", targetComplexField.getType().getName(), true),
                            StringConcatUtility.concatWithNamePrefix(this.getFormMetadataName(parameter), true)
                    ));
                }
            }

        }
        return warningValidateResult;
    }

    private Optional<Field> findFieldInFormSchema(Schema schema, SourceElementField sourceElementField) {
        CustomEntity sourceEntity = sourceElementField.getSourceEntity();
        CustomField sourceField = sourceElementField.getSourceField();

        Entity relateEntity = this.findEntityRescure(schema.getEntities(), sourceEntity);
        if (relateEntity != null) {
            // 获取对应的字段
            Optional<Field> optionalField = relateEntity.getType().getFields().stream().filter(t -> t.getId().equals(sourceField.getId()) && t.getCode().equals(sourceField.getCode())).findFirst();
            return optionalField;
        }
        return Optional.empty();
    }

    private Entity findEntityRescure(List<Entity> entityList, CustomEntity sourceEntity) {
        if (ListUtility.isEmpty(entityList)) {
            return null;
        }
        Optional<Entity> optionalEntity = entityList.stream().filter(t -> t.getId().equals(sourceEntity.getId()) && t.getCode().equals(sourceEntity.getCode())).findFirst();
        if (optionalEntity.isPresent()) {
            return optionalEntity.get();
        }

        List<Entity> hasChildrenEntities = entityList.stream().filter(t -> ListUtility.isNotEmpty(t.getType().getEntities())).collect(Collectors.toList());
        if (ListUtility.isNotEmpty(hasChildrenEntities)) {
            for (Entity entity : hasChildrenEntities) {
                Entity result = this.findEntityRescure(entity.getType().getEntities(), sourceEntity);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }


}
